home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / hity wydania / Ubuntu 9.10 PL / karmelkowy-koliberek-desktop-9.10-i386-PL.iso / casper / filesystem.squashfs / usr / lib / xulrunner-1.9.1.5 / components / nsLoginManagerPrompter.js < prev    next >
Text File  |  2009-11-09  |  45KB  |  1,241 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3.  *
  4.  * The contents of this file are subject to the Mozilla Public License Version
  5.  * 1.1 (the "License"); you may not use this file except in compliance with
  6.  * the License. You may obtain a copy of the License at
  7.  * http://www.mozilla.org/MPL/
  8.  *
  9.  * Software distributed under the License is distributed on an "AS IS" basis,
  10.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  11.  * for the specific language governing rights and limitations under the
  12.  * License.
  13.  *
  14.  * The Original Code is mozilla.org code.
  15.  *
  16.  * The Initial Developer of the Original Code is Mozilla Corporation.
  17.  * Portions created by the Initial Developer are Copyright (C) 2007
  18.  * the Initial Developer. All Rights Reserved.
  19.  *
  20.  * Contributor(s):
  21.  *  Justin Dolske <dolske@mozilla.com> (original author)
  22.  *  Ehsan Akhgari <ehsan.akhgari@gmail.com>
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38.  
  39. const Cc = Components.classes;
  40. const Ci = Components.interfaces;
  41. const Cr = Components.results;
  42.  
  43. Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
  44.  
  45. /*
  46.  * LoginManagerPromptFactory
  47.  *
  48.  * Implements nsIPromptFactory
  49.  *
  50.  * Invoked by NS_NewAuthPrompter2()
  51.  * [embedding/components/windowwatcher/src/nsPrompt.cpp]
  52.  */
  53. function LoginManagerPromptFactory() {}
  54.  
  55. LoginManagerPromptFactory.prototype = {
  56.  
  57.     classDescription : "LoginManagerPromptFactory",
  58.     contractID : "@mozilla.org/passwordmanager/authpromptfactory;1",
  59.     classID : Components.ID("{749e62f4-60ae-4569-a8a2-de78b649660e}"),
  60.     QueryInterface : XPCOMUtils.generateQI([Ci.nsIPromptFactory]),
  61.  
  62.     getPrompt : function (aWindow, aIID) {
  63.         var prompt = new LoginManagerPrompter().QueryInterface(aIID);
  64.         prompt.init(aWindow);
  65.         return prompt;
  66.     }
  67. }; // end of LoginManagerPromptFactory implementation
  68.  
  69.  
  70.  
  71.  
  72. /* ==================== LoginManagerPrompter ==================== */
  73.  
  74.  
  75.  
  76.  
  77. /*
  78.  * LoginManagerPrompter
  79.  *
  80.  * Implements interfaces for prompting the user to enter/save/change auth info.
  81.  *
  82.  * nsIAuthPrompt: Used by SeaMonkey, Thunderbird, but not Firefox.
  83.  *
  84.  * nsIAuthPrompt2: Is invoked by a channel for protocol-based authentication
  85.  * (eg HTTP Authenticate, FTP login).
  86.  *
  87.  * nsILoginManagerPrompter: Used by Login Manager for saving/changing logins
  88.  * found in HTML forms.
  89.  */
  90. function LoginManagerPrompter() {}
  91.  
  92. LoginManagerPrompter.prototype = {
  93.  
  94.     classDescription : "LoginManagerPrompter",
  95.     contractID : "@mozilla.org/login-manager/prompter;1",
  96.     classID : Components.ID("{8aa66d77-1bbb-45a6-991e-b8f47751c291}"),
  97.     QueryInterface : XPCOMUtils.generateQI([Ci.nsIAuthPrompt,
  98.                                             Ci.nsIAuthPrompt2,
  99.                                             Ci.nsILoginManagerPrompter]),
  100.  
  101.     _window        : null,
  102.     _debug         : false, // mirrors signon.debug
  103.  
  104.     __pwmgr : null, // Password Manager service
  105.     get _pwmgr() {
  106.         if (!this.__pwmgr)
  107.             this.__pwmgr = Cc["@mozilla.org/login-manager;1"].
  108.                            getService(Ci.nsILoginManager);
  109.         return this.__pwmgr;
  110.     },
  111.  
  112.     __logService : null, // Console logging service, used for debugging.
  113.     get _logService() {
  114.         if (!this.__logService)
  115.             this.__logService = Cc["@mozilla.org/consoleservice;1"].
  116.                                 getService(Ci.nsIConsoleService);
  117.         return this.__logService;
  118.     },
  119.  
  120.     __promptService : null, // Prompt service for user interaction
  121.     get _promptService() {
  122.         if (!this.__promptService)
  123.             this.__promptService =
  124.                 Cc["@mozilla.org/embedcomp/prompt-service;1"].
  125.                 getService(Ci.nsIPromptService2);
  126.         return this.__promptService;
  127.     },
  128.  
  129.  
  130.     __strBundle : null, // String bundle for L10N
  131.     get _strBundle() {
  132.         if (!this.__strBundle) {
  133.             var bunService = Cc["@mozilla.org/intl/stringbundle;1"].
  134.                              getService(Ci.nsIStringBundleService);
  135.             this.__strBundle = bunService.createBundle(
  136.                         "chrome://passwordmgr/locale/passwordmgr.properties");
  137.             if (!this.__strBundle)
  138.                 throw "String bundle for Login Manager not present!";
  139.         }
  140.  
  141.         return this.__strBundle;
  142.     },
  143.  
  144.  
  145.     __brandBundle : null, // String bundle for L10N
  146.     get _brandBundle() {
  147.         if (!this.__brandBundle) {
  148.             var bunService = Cc["@mozilla.org/intl/stringbundle;1"].
  149.                              getService(Ci.nsIStringBundleService);
  150.             this.__brandBundle = bunService.createBundle(
  151.                         "chrome://branding/locale/brand.properties");
  152.             if (!this.__brandBundle)
  153.                 throw "Branding string bundle not present!";
  154.         }
  155.  
  156.         return this.__brandBundle;
  157.     },
  158.  
  159.  
  160.     __ioService: null, // IO service for string -> nsIURI conversion
  161.     get _ioService() {
  162.         if (!this.__ioService)
  163.             this.__ioService = Cc["@mozilla.org/network/io-service;1"].
  164.                                getService(Ci.nsIIOService);
  165.         return this.__ioService;
  166.     },
  167.  
  168.  
  169.     __ellipsis : null,
  170.     get _ellipsis() {
  171.         if (!this.__ellipsis) {
  172.             this.__ellipsis = "\u2026";
  173.             try {
  174.                 var prefSvc = Cc["@mozilla.org/preferences-service;1"].
  175.                               getService(Ci.nsIPrefBranch);
  176.                 this.__ellipsis = prefSvc.getComplexValue("intl.ellipsis",
  177.                                       Ci.nsIPrefLocalizedString).data;
  178.             } catch (e) { }
  179.         }
  180.         return this.__ellipsis;
  181.     },
  182.  
  183.  
  184.     // Whether we are in private browsing mode
  185.     get _inPrivateBrowsing() {
  186.       // The Private Browsing service might not be available.
  187.       try {
  188.         var pbs = Cc["@mozilla.org/privatebrowsing;1"].
  189.                   getService(Ci.nsIPrivateBrowsingService);
  190.         return pbs.privateBrowsingEnabled;
  191.       } catch (e) {
  192.         return false;
  193.       }
  194.     },
  195.  
  196.  
  197.     /*
  198.      * log
  199.      *
  200.      * Internal function for logging debug messages to the Error Console window.
  201.      */
  202.     log : function (message) {
  203.         if (!this._debug)
  204.             return;
  205.  
  206.         dump("Pwmgr Prompter: " + message + "\n");
  207.         this._logService.logStringMessage("Pwmgr Prompter: " + message);
  208.     },
  209.  
  210.  
  211.  
  212.  
  213.     /* ---------- nsIAuthPrompt prompts ---------- */
  214.  
  215.  
  216.     /*
  217.      * prompt
  218.      *
  219.      * Wrapper around the prompt service prompt. Saving random fields here
  220.      * doesn't really make sense and therefore isn't implemented.
  221.      */
  222.     prompt : function (aDialogTitle, aText, aPasswordRealm,
  223.                        aSavePassword, aDefaultText, aResult) {
  224.         if (aSavePassword != Ci.nsIAuthPrompt.SAVE_PASSWORD_NEVER)
  225.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  226.  
  227.         this.log("===== prompt() called =====");
  228.  
  229.         if (aDefaultText) {
  230.             aResult.value = aDefaultText;
  231.         }
  232.  
  233.         return this._promptService.prompt(this._window,
  234.                aDialogTitle, aText, aResult, null, {});
  235.     },
  236.  
  237.  
  238.     /*
  239.      * promptUsernameAndPassword
  240.      *
  241.      * Looks up a username and password in the database. Will prompt the user
  242.      * with a dialog, even if a username and password are found.
  243.      */
  244.     promptUsernameAndPassword : function (aDialogTitle, aText, aPasswordRealm,
  245.                                          aSavePassword, aUsername, aPassword) {
  246.         this.log("===== promptUsernameAndPassword() called =====");
  247.  
  248.         if (aSavePassword == Ci.nsIAuthPrompt.SAVE_PASSWORD_FOR_SESSION)
  249.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  250.  
  251.         var selectedLogin = null;
  252.         var checkBox = { value : false };
  253.         var checkBoxLabel = null;
  254.         var [hostname, realm, unused] = this._getRealmInfo(aPasswordRealm);
  255.  
  256.         // If hostname is null, we can't save this login.
  257.         if (hostname) {
  258.             var canRememberLogin;
  259.             if (this._inPrivateBrowsing)
  260.                 canRememberLogin = false;
  261.             else
  262.                 canRememberLogin = (aSavePassword ==
  263.                                     Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY) &&
  264.                                    this._pwmgr.getLoginSavingEnabled(hostname);
  265.  
  266.             // if checkBoxLabel is null, the checkbox won't be shown at all.
  267.             if (canRememberLogin)
  268.                 checkBoxLabel = this._getLocalizedString("rememberPassword");
  269.  
  270.             // Look for existing logins.
  271.             var foundLogins = this._pwmgr.findLogins({}, hostname, null,
  272.                                                      realm);
  273.  
  274.             // XXX Like the original code, we can't deal with multiple
  275.             // account selection. (bug 227632)
  276.             if (foundLogins.length > 0) {
  277.                 selectedLogin = foundLogins[0];
  278.  
  279.                 // If the caller provided a username, try to use it. If they
  280.                 // provided only a password, this will try to find a password-only
  281.                 // login (or return null if none exists).
  282.                 if (aUsername.value)
  283.                     selectedLogin = this._repickSelectedLogin(foundLogins,
  284.                                                               aUsername.value);
  285.  
  286.                 if (selectedLogin) {
  287.                     checkBox.value = true;
  288.                     aUsername.value = selectedLogin.username;
  289.                     // If the caller provided a password, prefer it.
  290.                     if (!aPassword.value)
  291.                         aPassword.value = selectedLogin.password;
  292.                 }
  293.             }
  294.         }
  295.  
  296.         var ok = this._promptService.promptUsernameAndPassword(this._window,
  297.                     aDialogTitle, aText, aUsername, aPassword,
  298.                     checkBoxLabel, checkBox);
  299.  
  300.         if (!ok || !checkBox.value || !hostname)
  301.             return ok;
  302.  
  303.         if (!aPassword.value) {
  304.             this.log("No password entered, so won't offer to save.");
  305.             return ok;
  306.         }
  307.  
  308.         var newLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
  309.                        createInstance(Ci.nsILoginInfo);
  310.         newLogin.init(hostname, null, realm, aUsername.value, aPassword.value,
  311.                       "", "");
  312.  
  313.         // XXX We can't prompt with multiple logins yet (bug 227632), so
  314.         // the entered login might correspond to an existing login
  315.         // other than the one we originally selected.
  316.         selectedLogin = this._repickSelectedLogin(foundLogins, aUsername.value);
  317.  
  318.         // If we didn't find an existing login, or if the username
  319.         // changed, save as a new login.
  320.         if (!selectedLogin) {
  321.             // add as new
  322.             this.log("New login seen for " + realm);
  323.             this._pwmgr.addLogin(newLogin);
  324.         } else if (aPassword.value != selectedLogin.password) {
  325.             // update password
  326.             this.log("Updating password for  " + realm);
  327.             this._pwmgr.modifyLogin(selectedLogin, newLogin);
  328.         } else {
  329.             this.log("Login unchanged, no further action needed.");
  330.         }
  331.  
  332.         return ok;
  333.     },
  334.  
  335.  
  336.     /*
  337.      * promptPassword
  338.      *
  339.      * If a password is found in the database for the password realm, it is
  340.      * returned straight away without displaying a dialog.
  341.      *
  342.      * If a password is not found in the database, the user will be prompted
  343.      * with a dialog with a text field and ok/cancel buttons. If the user
  344.      * allows it, then the password will be saved in the database.
  345.      */
  346.     promptPassword : function (aDialogTitle, aText, aPasswordRealm,
  347.                                aSavePassword, aPassword) {
  348.         this.log("===== promptPassword called() =====");
  349.  
  350.         if (aSavePassword == Ci.nsIAuthPrompt.SAVE_PASSWORD_FOR_SESSION)
  351.             throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  352.  
  353.         var checkBox = { value : false };
  354.         var checkBoxLabel = null;
  355.         var [hostname, realm, username] = this._getRealmInfo(aPasswordRealm);
  356.  
  357.         username = decodeURIComponent(username);
  358.  
  359.         // If hostname is null, we can't save this login.
  360.         if (hostname && !this._inPrivateBrowsing) {
  361.           var canRememberLogin = (aSavePassword ==
  362.                                   Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY) &&
  363.                                  this._pwmgr.getLoginSavingEnabled(hostname);
  364.   
  365.           // if checkBoxLabel is null, the checkbox won't be shown at all.
  366.           if (canRememberLogin)
  367.               checkBoxLabel = this._getLocalizedString("rememberPassword");
  368.   
  369.           if (!aPassword.value) {
  370.               // Look for existing logins.
  371.               var foundLogins = this._pwmgr.findLogins({}, hostname, null,
  372.                                                        realm);
  373.   
  374.               // XXX Like the original code, we can't deal with multiple
  375.               // account selection (bug 227632). We can deal with finding the
  376.               // account based on the supplied username - but in this case we'll
  377.               // just return the first match.
  378.               for (var i = 0; i < foundLogins.length; ++i) {
  379.                   if (foundLogins[i].username == username) {
  380.                       aPassword.value = foundLogins[i].password;
  381.                       // wallet returned straight away, so this mimics that code
  382.                       return true;
  383.                   }
  384.               }
  385.           }
  386.         }
  387.  
  388.         var ok = this._promptService.promptPassword(this._window, aDialogTitle,
  389.                                                     aText, aPassword,
  390.                                                     checkBoxLabel, checkBox);
  391.  
  392.         if (ok && checkBox.value && hostname && aPassword.value) {
  393.             var newLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
  394.                            createInstance(Ci.nsILoginInfo);
  395.             newLogin.init(hostname, null, realm, username,
  396.                           aPassword.value, "", "");
  397.  
  398.             this.log("New login seen for " + realm);
  399.  
  400.             this._pwmgr.addLogin(newLogin);
  401.         }
  402.  
  403.         return ok;
  404.     },
  405.  
  406.     /* ---------- nsIAuthPrompt helpers ---------- */
  407.  
  408.  
  409.     /**
  410.      * Given aRealmString, such as "http://user@example.com/foo", returns an
  411.      * array of:
  412.      *   - the formatted hostname
  413.      *   - the realm (hostname + path)
  414.      *   - the username, if present
  415.      *
  416.      * If aRealmString is in the format produced by NS_GetAuthKey for HTTP[S]
  417.      * channels, e.g. "example.com:80 (httprealm)", null is returned for all
  418.      * arguments to let callers know the login can't be saved because we don't
  419.      * know whether it's http or https.
  420.      */
  421.     _getRealmInfo : function (aRealmString) {
  422.         var httpRealm = /^.+ \(.+\)$/;
  423.         if (httpRealm.test(aRealmString))
  424.             return [null, null, null];
  425.  
  426.         var uri = this._ioService.newURI(aRealmString, null, null);
  427.         var pathname = "";
  428.  
  429.         if (uri.path != "/")
  430.             pathname = uri.path;
  431.  
  432.         var formattedHostname = this._getFormattedHostname(uri);
  433.  
  434.         return [formattedHostname, formattedHostname + pathname, uri.username];
  435.     },
  436.  
  437.     /* ---------- nsIAuthPrompt2 prompts ---------- */
  438.  
  439.  
  440.  
  441.  
  442.     /*
  443.      * promptAuth
  444.      *
  445.      * Implementation of nsIAuthPrompt2.
  446.      *
  447.      * nsIChannel aChannel
  448.      * int        aLevel
  449.      * nsIAuthInformation aAuthInfo
  450.      */
  451.     promptAuth : function (aChannel, aLevel, aAuthInfo) {
  452.         var selectedLogin = null;
  453.         var checkbox = { value : false };
  454.         var checkboxLabel = null;
  455.         var epicfail = false;
  456.  
  457.         try {
  458.  
  459.             this.log("===== promptAuth called =====");
  460.  
  461.             // If the user submits a login but it fails, we need to remove the
  462.             // notification bar that was displayed. Conveniently, the user will
  463.             // be prompted for authentication again, which brings us here.
  464.             var notifyBox = this._getNotifyBox();
  465.             if (notifyBox)
  466.                 this._removeLoginNotifications(notifyBox);
  467.  
  468.             var [hostname, httpRealm] = this._getAuthTarget(aChannel, aAuthInfo);
  469.  
  470.  
  471.             // Looks for existing logins to prefill the prompt with.
  472.             var foundLogins = this._pwmgr.findLogins({},
  473.                                         hostname, null, httpRealm);
  474.             this.log("found " + foundLogins.length + " matching logins.");
  475.  
  476.             // XXX Can't select from multiple accounts yet. (bug 227632)
  477.             if (foundLogins.length > 0) {
  478.                 selectedLogin = foundLogins[0];
  479.                 this._SetAuthInfo(aAuthInfo, selectedLogin.username,
  480.                                              selectedLogin.password);
  481.                 checkbox.value = true;
  482.             }
  483.  
  484.             var canRememberLogin = this._pwmgr.getLoginSavingEnabled(hostname);
  485.             if (this._inPrivateBrowsing)
  486.               canRememberLogin = false;
  487.         
  488.             // if checkboxLabel is null, the checkbox won't be shown at all.
  489.             if (canRememberLogin && !notifyBox)
  490.                 checkboxLabel = this._getLocalizedString("rememberPassword");
  491.         } catch (e) {
  492.             // Ignore any errors and display the prompt anyway.
  493.             epicfail = true;
  494.             Components.utils.reportError("LoginManagerPrompter: " +
  495.                 "Epic fail in promptAuth: " + e + "\n");
  496.         }
  497.  
  498.         var ok = this._promptService.promptAuth(this._window, aChannel,
  499.                                 aLevel, aAuthInfo, checkboxLabel, checkbox);
  500.  
  501.         // If there's a notification box, use it to allow the user to
  502.         // determine if the login should be saved. If there isn't a
  503.         // notification box, only save the login if the user set the
  504.         // checkbox to do so.
  505.         var rememberLogin = notifyBox ? canRememberLogin : checkbox.value;
  506.         if (!ok || !rememberLogin || epicfail)
  507.             return ok;
  508.  
  509.         try {
  510.             var [username, password] = this._GetAuthInfo(aAuthInfo);
  511.  
  512.             if (!password) {
  513.                 this.log("No password entered, so won't offer to save.");
  514.                 return ok;
  515.             }
  516.  
  517.             var newLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].
  518.                            createInstance(Ci.nsILoginInfo);
  519.             newLogin.init(hostname, null, httpRealm,
  520.                           username, password, "", "");
  521.  
  522.             // XXX We can't prompt with multiple logins yet (bug 227632), so
  523.             // the entered login might correspond to an existing login
  524.             // other than the one we originally selected.
  525.             selectedLogin = this._repickSelectedLogin(foundLogins, username);
  526.  
  527.             // If we didn't find an existing login, or if the username
  528.             // changed, save as a new login.
  529.             if (!selectedLogin) {
  530.                 // add as new
  531.                 this.log("New login seen for " + username +
  532.                          " @ " + hostname + " (" + httpRealm + ")");
  533.                 if (notifyBox)
  534.                     this._showSaveLoginNotification(notifyBox, newLogin);
  535.                 else
  536.                     this._pwmgr.addLogin(newLogin);
  537.  
  538.             } else if (password != selectedLogin.password) {
  539.  
  540.                 this.log("Updating password for " + username +
  541.                          " @ " + hostname + " (" + httpRealm + ")");
  542.                 if (notifyBox)
  543.                     this._showChangeLoginNotification(notifyBox,
  544.                                                       selectedLogin, newLogin);
  545.                 else
  546.                     this._pwmgr.modifyLogin(selectedLogin, newLogin);
  547.  
  548.             } else {
  549.                 this.log("Login unchanged, no further action needed.");
  550.             }
  551.         } catch (e) {
  552.             Components.utils.reportError("LoginManagerPrompter: " +
  553.                 "Fail2 in promptAuth: " + e + "\n");
  554.         }
  555.  
  556.         return ok;
  557.     },
  558.  
  559.     asyncPromptAuth : function () {
  560.         return NS_ERROR_NOT_IMPLEMENTED;
  561.     },
  562.  
  563.  
  564.  
  565.  
  566.     /* ---------- nsILoginManagerPrompter prompts ---------- */
  567.  
  568.  
  569.  
  570.  
  571.     /*
  572.      * init
  573.      *
  574.      */
  575.     init : function (aWindow) {
  576.         this._window = aWindow;
  577.  
  578.         var prefBranch = Cc["@mozilla.org/preferences-service;1"].
  579.                          getService(Ci.nsIPrefService).getBranch("signon.");
  580.         this._debug = prefBranch.getBoolPref("debug");
  581.         this.log("===== initialized =====");
  582.     },
  583.  
  584.  
  585.     /*
  586.      * promptToSavePassword
  587.      *
  588.      */
  589.     promptToSavePassword : function (aLogin) {
  590.         var notifyBox = this._getNotifyBox();
  591.  
  592.         if (notifyBox)
  593.             this._showSaveLoginNotification(notifyBox, aLogin);
  594.         else
  595.             this._showSaveLoginDialog(aLogin);
  596.     },
  597.  
  598.  
  599.     /*
  600.      * _showLoginNotification
  601.      *
  602.      * Displays a notification bar.
  603.      *
  604.      */
  605.     _showLoginNotification : function (aNotifyBox, aName, aText, aButtons) {
  606.         var oldBar = aNotifyBox.getNotificationWithValue(aName);
  607.         const priority = aNotifyBox.PRIORITY_INFO_MEDIUM;
  608.  
  609.         this.log("Adding new " + aName + " notification bar");
  610.         var newBar = aNotifyBox.appendNotification(
  611.                                 aText, aName,
  612.                                 "chrome://mozapps/skin/passwordmgr/key.png",
  613.                                 priority, aButtons);
  614.  
  615.         // The page we're going to hasn't loaded yet, so we want to persist
  616.         // across the first location change.
  617.         newBar.persistence++;
  618.  
  619.         // Sites like Gmail perform a funky redirect dance before you end up
  620.         // at the post-authentication page. I don't see a good way to
  621.         // heuristically determine when to ignore such location changes, so
  622.         // we'll try ignoring location changes based on a time interval.
  623.         newBar.timeout = Date.now() + 20000; // 20 seconds
  624.  
  625.         if (oldBar) {
  626.             this.log("(...and removing old " + aName + " notification bar)");
  627.             aNotifyBox.removeNotification(oldBar);
  628.         }
  629.     },
  630.  
  631.  
  632.     /*
  633.      * _showSaveLoginNotification
  634.      *
  635.      * Displays a notification bar (rather than a popup), to allow the user to
  636.      * save the specified login. This allows the user to see the results of
  637.      * their login, and only save a login which they know worked.
  638.      *
  639.      */
  640.     _showSaveLoginNotification : function (aNotifyBox, aLogin) {
  641.  
  642.         // Ugh. We can't use the strings from the popup window, because they
  643.         // have the access key marked in the string (eg "Mo&zilla"), along
  644.         // with some weird rules for handling access keys that do not occur
  645.         // in the string, for L10N. See commonDialog.js's setLabelForNode().
  646.         var neverButtonText =
  647.               this._getLocalizedString("notifyBarNeverForSiteButtonText");
  648.         var neverButtonAccessKey =
  649.               this._getLocalizedString("notifyBarNeverForSiteButtonAccessKey");
  650.         var rememberButtonText =
  651.               this._getLocalizedString("notifyBarRememberButtonText");
  652.         var rememberButtonAccessKey =
  653.               this._getLocalizedString("notifyBarRememberButtonAccessKey");
  654.         var notNowButtonText =
  655.               this._getLocalizedString("notifyBarNotNowButtonText");
  656.         var notNowButtonAccessKey =
  657.               this._getLocalizedString("notifyBarNotNowButtonAccessKey");
  658.  
  659.         var brandShortName =  "toolkit@mozilla.org";
  660.         try {
  661.                 brandShortName =
  662.                       this._brandBundle.GetStringFromName("brandShortName");
  663.         } catch (e) {
  664.                 this.log ("no brandShortName available for prompting - most likely incomplete embedding.");
  665.         }
  666.  
  667.         var displayHost = this._getShortDisplayHost(aLogin.hostname);
  668.         var notificationText;
  669.         if (aLogin.username) {
  670.             var displayUser = this._sanitizeUsername(aLogin.username);
  671.             notificationText  = this._getLocalizedString(
  672.                                         "saveLoginText",
  673.                                         [brandShortName, displayUser, displayHost]);
  674.         } else {
  675.             notificationText  = this._getLocalizedString(
  676.                                         "saveLoginTextNoUsername",
  677.                                         [brandShortName, displayHost]);
  678.         }
  679.  
  680.         // The callbacks in |buttons| have a closure to access the variables
  681.         // in scope here; set one to |this._pwmgr| so we can get back to pwmgr
  682.         // without a getService() call.
  683.         var pwmgr = this._pwmgr;
  684.  
  685.  
  686.         var buttons = [
  687.             // "Remember" button
  688.             {
  689.                 label:     rememberButtonText,
  690.                 accessKey: rememberButtonAccessKey,
  691.                 popup:     null,
  692.                 callback: function(aNotificationBar, aButton) {
  693.                     pwmgr.addLogin(aLogin);
  694.                 }
  695.             },
  696.  
  697.             // "Never for this site" button
  698.             {
  699.                 label:     neverButtonText,
  700.                 accessKey: neverButtonAccessKey,
  701.                 popup:     null,
  702.                 callback: function(aNotificationBar, aButton) {
  703.                     pwmgr.setLoginSavingEnabled(aLogin.hostname, false);
  704.                 }
  705.             },
  706.  
  707.             // "Not now" button
  708.             {
  709.                 label:     notNowButtonText,
  710.                 accessKey: notNowButtonAccessKey,
  711.                 popup:     null,
  712.                 callback:  function() { /* NOP */ } 
  713.             }
  714.         ];
  715.  
  716.         this._showLoginNotification(aNotifyBox, "password-save",
  717.              notificationText, buttons);
  718.     },
  719.  
  720.  
  721.     /*
  722.      * _removeLoginNotifications
  723.      *
  724.      */
  725.     _removeLoginNotifications : function (aNotifyBox) {
  726.         var oldBar = aNotifyBox.getNotificationWithValue("password-save");
  727.         if (oldBar) {
  728.             this.log("Removing save-password notification bar.");
  729.             aNotifyBox.removeNotification(oldBar);
  730.         }
  731.  
  732.         oldBar = aNotifyBox.getNotificationWithValue("password-change");
  733.         if (oldBar) {
  734.             this.log("Removing change-password notification bar.");
  735.             aNotifyBox.removeNotification(oldBar);
  736.         }
  737.     },
  738.  
  739.  
  740.     /*
  741.      * _showSaveLoginDialog
  742.      *
  743.      * Called when we detect a new login in a form submission,
  744.      * asks the user what to do.
  745.      *
  746.      */
  747.     _showSaveLoginDialog : function (aLogin) {
  748.         const buttonFlags = Ci.nsIPrompt.BUTTON_POS_1_DEFAULT +
  749.             (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
  750.             (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1) +
  751.             (Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_2);
  752.  
  753.         var brandShortName =  "toolkit@mozilla.org";
  754.         try {
  755.                 brandShortName =
  756.                       this._brandBundle.GetStringFromName("brandShortName");
  757.         } catch (e) {
  758.                 this.log ("no brandShortName available for prompting - most likely incomplete embedding.");
  759.         }
  760.  
  761.         var displayHost = this._getShortDisplayHost(aLogin.hostname);
  762.         var dialogText;
  763.         if (aLogin.username) {
  764.             var displayUser = this._sanitizeUsername(aLogin.username);
  765.             dialogText = this._getLocalizedString(
  766.                                  "saveLoginText",
  767.                                  [brandShortName, displayUser, displayHost]);
  768.         } else {
  769.             dialogText = this._getLocalizedString(
  770.                                  "saveLoginTextNoUsername",
  771.                                  [brandShortName, displayHost]);
  772.         }
  773.         var dialogTitle        = this._getLocalizedString(
  774.                                         "savePasswordTitle");
  775.         var neverButtonText    = this._getLocalizedString(
  776.                                         "neverForSiteButtonText");
  777.         var rememberButtonText = this._getLocalizedString(
  778.                                         "rememberButtonText");
  779.         var notNowButtonText   = this._getLocalizedString(
  780.                                         "notNowButtonText");
  781.  
  782.         this.log("Prompting user to save/ignore login");
  783.         var userChoice = this._promptService.confirmEx(this._window,
  784.                                             dialogTitle, dialogText,
  785.                                             buttonFlags, rememberButtonText,
  786.                                             notNowButtonText, neverButtonText,
  787.                                             null, {});
  788.         //  Returns:
  789.         //   0 - Save the login
  790.         //   1 - Ignore the login this time
  791.         //   2 - Never save logins for this site
  792.         if (userChoice == 2) {
  793.             this.log("Disabling " + aLogin.hostname + " logins by request.");
  794.             this._pwmgr.setLoginSavingEnabled(aLogin.hostname, false);
  795.         } else if (userChoice == 0) {
  796.             this.log("Saving login for " + aLogin.hostname);
  797.             this._pwmgr.addLogin(aLogin);
  798.         } else {
  799.             // userChoice == 1 --> just ignore the login.
  800.             this.log("Ignoring login.");
  801.         }
  802.     },
  803.  
  804.  
  805.     /*
  806.      * promptToChangePassword
  807.      *
  808.      * Called when we think we detect a password change for an existing
  809.      * login, when the form being submitted contains multiple password
  810.      * fields.
  811.      *
  812.      */
  813.     promptToChangePassword : function (aOldLogin, aNewLogin) {
  814.         var notifyBox = this._getNotifyBox();
  815.  
  816.         if (notifyBox)
  817.             this._showChangeLoginNotification(notifyBox, aOldLogin, aNewLogin);
  818.         else
  819.             this._showChangeLoginDialog(aOldLogin, aNewLogin);
  820.     },
  821.  
  822.  
  823.     /*
  824.      * _showChangeLoginNotification
  825.      *
  826.      * Shows the Change Password notification bar.
  827.      *
  828.      */
  829.     _showChangeLoginNotification : function (aNotifyBox, aOldLogin, aNewLogin) {
  830.         var notificationText;
  831.         if (aOldLogin.username)
  832.             notificationText  = this._getLocalizedString(
  833.                                           "passwordChangeText",
  834.                                           [aOldLogin.username]);
  835.         else
  836.             notificationText  = this._getLocalizedString(
  837.                                           "passwordChangeTextNoUser");
  838.  
  839.         var changeButtonText =
  840.               this._getLocalizedString("notifyBarChangeButtonText");
  841.         var changeButtonAccessKey =
  842.               this._getLocalizedString("notifyBarChangeButtonAccessKey");
  843.         var dontChangeButtonText =
  844.               this._getLocalizedString("notifyBarDontChangeButtonText");
  845.         var dontChangeButtonAccessKey =
  846.               this._getLocalizedString("notifyBarDontChangeButtonAccessKey");
  847.  
  848.         // The callbacks in |buttons| have a closure to access the variables
  849.         // in scope here; set one to |this._pwmgr| so we can get back to pwmgr
  850.         // without a getService() call.
  851.         var pwmgr = this._pwmgr;
  852.  
  853.         var buttons = [
  854.             // "Yes" button
  855.             {
  856.                 label:     changeButtonText,
  857.                 accessKey: changeButtonAccessKey,
  858.                 popup:     null,
  859.                 callback:  function(aNotificationBar, aButton) {
  860.                     pwmgr.modifyLogin(aOldLogin, aNewLogin);
  861.                 }
  862.             },
  863.  
  864.             // "No" button
  865.             {
  866.                 label:     dontChangeButtonText,
  867.                 accessKey: dontChangeButtonAccessKey,
  868.                 popup:     null,
  869.                 callback:  function(aNotificationBar, aButton) {
  870.                     // do nothing
  871.                 }
  872.             }
  873.         ];
  874.  
  875.         this._showLoginNotification(aNotifyBox, "password-change",
  876.              notificationText, buttons);
  877.     },
  878.  
  879.  
  880.     /*
  881.      * _showChangeLoginDialog
  882.      *
  883.      * Shows the Change Password dialog.
  884.      *
  885.      */
  886.     _showChangeLoginDialog : function (aOldLogin, aNewLogin) {
  887.         const buttonFlags = Ci.nsIPrompt.STD_YES_NO_BUTTONS;
  888.  
  889.         var dialogText;
  890.         if (aOldLogin.username)
  891.             dialogText  = this._getLocalizedString(
  892.                                     "passwordChangeText",
  893.                                     [aOldLogin.username]);
  894.         else
  895.             dialogText  = this._getLocalizedString(
  896.                                     "passwordChangeTextNoUser");
  897.  
  898.         var dialogTitle = this._getLocalizedString(
  899.                                     "passwordChangeTitle");
  900.  
  901.         // returns 0 for yes, 1 for no.
  902.         var ok = !this._promptService.confirmEx(this._window,
  903.                                 dialogTitle, dialogText, buttonFlags,
  904.                                 null, null, null,
  905.                                 null, {});
  906.         if (ok) {
  907.             this.log("Updating password for user " + aOldLogin.username);
  908.             this._pwmgr.modifyLogin(aOldLogin, aNewLogin);
  909.         }
  910.     },
  911.  
  912.  
  913.     /*
  914.      * promptToChangePasswordWithUsernames
  915.      *
  916.      * Called when we detect a password change in a form submission, but we
  917.      * don't know which existing login (username) it's for. Asks the user
  918.      * to select a username and confirm the password change.
  919.      *
  920.      * Note: The caller doesn't know the username for aNewLogin, so this
  921.      *       function fills in .username and .usernameField with the values
  922.      *       from the login selected by the user.
  923.      * 
  924.      * Note; XPCOM stupidity: |count| is just |logins.length|.
  925.      */
  926.     promptToChangePasswordWithUsernames : function (logins, count, aNewLogin) {
  927.         const buttonFlags = Ci.nsIPrompt.STD_YES_NO_BUTTONS;
  928.  
  929.         var usernames = logins.map(function (l) l.username);
  930.         var dialogText  = this._getLocalizedString("userSelectText");
  931.         var dialogTitle = this._getLocalizedString("passwordChangeTitle");
  932.         var selectedIndex = { value: null };
  933.  
  934.         // If user selects ok, outparam.value is set to the index
  935.         // of the selected username.
  936.         var ok = this._promptService.select(this._window,
  937.                                 dialogTitle, dialogText,
  938.                                 usernames.length, usernames,
  939.                                 selectedIndex);
  940.         if (ok) {
  941.             // Now that we know which login to change the password for,
  942.             // update the missing username info in the aNewLogin.
  943.  
  944.             var selectedLogin = logins[selectedIndex.value];
  945.  
  946.             this.log("Updating password for user " + selectedLogin.username);
  947.  
  948.             aNewLogin.username      = selectedLogin.username;
  949.             aNewLogin.usernameField = selectedLogin.usernameField;
  950.  
  951.             this._pwmgr.modifyLogin(selectedLogin, aNewLogin);
  952.         }
  953.     },
  954.  
  955.  
  956.  
  957.  
  958.     /* ---------- Internal Methods ---------- */
  959.  
  960.  
  961.  
  962.  
  963.     /*
  964.      * _getNotifyBox
  965.      *
  966.      * Returns the notification box to this prompter, or null if there isn't
  967.      * a notification box available.
  968.      */
  969.     _getNotifyBox : function () {
  970.         var notifyBox = null;
  971.  
  972.         // Given a content DOM window, returns the chrome window it's in.
  973.         function getChromeWindow(aWindow) {
  974.             var chromeWin = aWindow 
  975.                                 .QueryInterface(Ci.nsIInterfaceRequestor)
  976.                                 .getInterface(Ci.nsIWebNavigation)
  977.                                 .QueryInterface(Ci.nsIDocShellTreeItem)
  978.                                 .rootTreeItem
  979.                                 .QueryInterface(Ci.nsIInterfaceRequestor)
  980.                                 .getInterface(Ci.nsIDOMWindow)
  981.                                 .QueryInterface(Ci.nsIDOMChromeWindow);
  982.             return chromeWin;
  983.         }
  984.  
  985.         try {
  986.             // Get topmost window, in case we're in a frame.
  987.             var notifyWindow = this._window.top
  988.  
  989.             // Some sites pop up a temporary login window, when disappears
  990.             // upon submission of credentials. We want to put the notification
  991.             // bar in the opener window if this seems to be happening.
  992.             if (notifyWindow.opener) {
  993.                 var chromeDoc = getChromeWindow(notifyWindow)
  994.                                     .document.documentElement;
  995.                 var webnav = notifyWindow
  996.                                     .QueryInterface(Ci.nsIInterfaceRequestor)
  997.                                     .getInterface(Ci.nsIWebNavigation);
  998.  
  999.                 // Check to see if the current window was opened with chrome
  1000.                 // disabled, and if so use the opener window. But if the window
  1001.                 // has been used to visit other pages (ie, has a history),
  1002.                 // assume it'll stick around and *don't* use the opener.
  1003.                 if (chromeDoc.getAttribute("chromehidden") &&
  1004.                     webnav.sessionHistory.count == 1) {
  1005.                     this.log("Using opener window for notification bar.");
  1006.                     notifyWindow = notifyWindow.opener;
  1007.                 }
  1008.             }
  1009.  
  1010.  
  1011.             // Get the chrome window for the content window we're using.
  1012.             // .wrappedJSObject needed here -- see bug 422974 comment 5.
  1013.             var chromeWin = getChromeWindow(notifyWindow).wrappedJSObject;
  1014.  
  1015.             if (chromeWin.getNotificationBox)
  1016.                 notifyBox = chromeWin.getNotificationBox(notifyWindow);
  1017.             else
  1018.                 this.log("getNotificationBox() not available on window");
  1019.  
  1020.         } catch (e) {
  1021.             // If any errors happen, just assume no notification box.
  1022.             this.log("No notification box available: " + e)
  1023.         }
  1024.  
  1025.         return notifyBox;
  1026.     },
  1027.  
  1028.  
  1029.     /*
  1030.      * _repickSelectedLogin
  1031.      *
  1032.      * The user might enter a login that isn't the one we prefilled, but
  1033.      * is the same as some other existing login. So, pick a login with a
  1034.      * matching username, or return null.
  1035.      */
  1036.     _repickSelectedLogin : function (foundLogins, username) {
  1037.         for (var i = 0; i < foundLogins.length; i++)
  1038.             if (foundLogins[i].username == username)
  1039.                 return foundLogins[i];
  1040.         return null;
  1041.     },
  1042.  
  1043.     
  1044.     /*
  1045.      * _getLocalizedString
  1046.      *
  1047.      * Can be called as:
  1048.      *   _getLocalizedString("key1");
  1049.      *   _getLocalizedString("key2", ["arg1"]);
  1050.      *   _getLocalizedString("key3", ["arg1", "arg2"]);
  1051.      *   (etc)
  1052.      *
  1053.      * Returns the localized string for the specified key,
  1054.      * formatted if required.
  1055.      *
  1056.      */ 
  1057.     _getLocalizedString : function (key, formatArgs) {
  1058.         if (formatArgs)
  1059.             return this._strBundle.formatStringFromName(
  1060.                                         key, formatArgs, formatArgs.length);
  1061.         else
  1062.             return this._strBundle.GetStringFromName(key);
  1063.     },
  1064.  
  1065.  
  1066.     /*
  1067.      * _sanitizeUsername
  1068.      *
  1069.      * Sanitizes the specified username, by stripping quotes and truncating if
  1070.      * it's too long. This helps prevent an evil site from messing with the
  1071.      * "save password?" prompt too much.
  1072.      */
  1073.     _sanitizeUsername : function (username) {
  1074.         if (username.length > 30) {
  1075.             username = username.substring(0, 30);
  1076.             username += this._ellipsis;
  1077.         }
  1078.         return username.replace(/['"]/g, "");
  1079.     },
  1080.  
  1081.  
  1082.     /*
  1083.      * _getFormattedHostname
  1084.      *
  1085.      * The aURI parameter may either be a string uri, or an nsIURI instance.
  1086.      *
  1087.      * Returns the hostname to use in a nsILoginInfo object (for example,
  1088.      * "http://example.com").
  1089.      */
  1090.     _getFormattedHostname : function (aURI) {
  1091.         var uri;
  1092.         if (aURI instanceof Ci.nsIURI) {
  1093.             uri = aURI;
  1094.         } else {
  1095.             uri = this._ioService.newURI(aURI, null, null);
  1096.         }
  1097.         var scheme = uri.scheme;
  1098.  
  1099.         var hostname = scheme + "://" + uri.host;
  1100.  
  1101.         // If the URI explicitly specified a port, only include it when
  1102.         // it's not the default. (We never want "http://foo.com:80")
  1103.         port = uri.port;
  1104.         if (port != -1) {
  1105.             var handler = this._ioService.getProtocolHandler(scheme);
  1106.             if (port != handler.defaultPort)
  1107.                 hostname += ":" + port;
  1108.         }
  1109.  
  1110.         return hostname;
  1111.     },
  1112.  
  1113.  
  1114.     /*
  1115.      * _getShortDisplayHost
  1116.      *
  1117.      * Converts a login's hostname field (a URL) to a short string for
  1118.      * prompting purposes. Eg, "http://foo.com" --> "foo.com", or
  1119.      * "ftp://www.site.co.uk" --> "site.co.uk".
  1120.      */
  1121.     _getShortDisplayHost: function (aURIString) {
  1122.         var displayHost;
  1123.  
  1124.         var eTLDService = Cc["@mozilla.org/network/effective-tld-service;1"].
  1125.                           getService(Ci.nsIEffectiveTLDService);
  1126.         var idnService = Cc["@mozilla.org/network/idn-service;1"].
  1127.                          getService(Ci.nsIIDNService);
  1128.         try {
  1129.             var uri = this._ioService.newURI(aURIString, null, null);
  1130.             var baseDomain = eTLDService.getBaseDomain(uri);
  1131.             displayHost = idnService.convertToDisplayIDN(baseDomain, {});
  1132.         } catch (e) {
  1133.             this.log("_getShortDisplayHost couldn't process " + aURIString);
  1134.         }
  1135.  
  1136.         if (!displayHost)
  1137.             displayHost = aURIString;
  1138.  
  1139.         return displayHost;
  1140.     },
  1141.  
  1142.  
  1143.     /*
  1144.      * _getAuthTarget
  1145.      *
  1146.      * Returns the hostname and realm for which authentication is being
  1147.      * requested, in the format expected to be used with nsILoginInfo.
  1148.      */
  1149.     _getAuthTarget : function (aChannel, aAuthInfo) {
  1150.         var hostname, realm;
  1151.  
  1152.         // If our proxy is demanding authentication, don't use the
  1153.         // channel's actual destination.
  1154.         if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) {
  1155.             this.log("getAuthTarget is for proxy auth");
  1156.             if (!(aChannel instanceof Ci.nsIProxiedChannel))
  1157.                 throw "proxy auth needs nsIProxiedChannel";
  1158.  
  1159.             var info = aChannel.proxyInfo;
  1160.             if (!info)
  1161.                 throw "proxy auth needs nsIProxyInfo";
  1162.  
  1163.             // Proxies don't have a scheme, but we'll use "moz-proxy://"
  1164.             // so that it's more obvious what the login is for.
  1165.             var idnService = Cc["@mozilla.org/network/idn-service;1"].
  1166.                              getService(Ci.nsIIDNService);
  1167.             hostname = "moz-proxy://" +
  1168.                         idnService.convertUTF8toACE(info.host) +
  1169.                         ":" + info.port;
  1170.             realm = aAuthInfo.realm;
  1171.             if (!realm)
  1172.                 realm = hostname;
  1173.  
  1174.             return [hostname, realm];
  1175.         }
  1176.  
  1177.         hostname = this._getFormattedHostname(aChannel.URI);
  1178.  
  1179.         // If a HTTP WWW-Authenticate header specified a realm, that value
  1180.         // will be available here. If it wasn't set or wasn't HTTP, we'll use
  1181.         // the formatted hostname instead.
  1182.         realm = aAuthInfo.realm;
  1183.         if (!realm)
  1184.             realm = hostname;
  1185.  
  1186.         return [hostname, realm];
  1187.     },
  1188.  
  1189.  
  1190.     /**
  1191.      * Returns [username, password] as extracted from aAuthInfo (which
  1192.      * holds this info after having prompted the user).
  1193.      *
  1194.      * If the authentication was for a Windows domain, we'll prepend the
  1195.      * return username with the domain. (eg, "domain\user")
  1196.      */
  1197.     _GetAuthInfo : function (aAuthInfo) {
  1198.         var username, password;
  1199.  
  1200.         var flags = aAuthInfo.flags;
  1201.         if (flags & Ci.nsIAuthInformation.NEED_DOMAIN && aAuthInfo.domain)
  1202.             username = aAuthInfo.domain + "\\" + aAuthInfo.username;
  1203.         else
  1204.             username = aAuthInfo.username;
  1205.  
  1206.         password = aAuthInfo.password;
  1207.  
  1208.         return [username, password];
  1209.     },
  1210.  
  1211.  
  1212.     /**
  1213.      * Given a username (possibly in DOMAIN\user form) and password, parses the
  1214.      * domain out of the username if necessary and sets domain, username and
  1215.      * password on the auth information object.
  1216.      */
  1217.     _SetAuthInfo : function (aAuthInfo, username, password) {
  1218.         var flags = aAuthInfo.flags;
  1219.         if (flags & Ci.nsIAuthInformation.NEED_DOMAIN) {
  1220.             // Domain is separated from username by a backslash
  1221.             var idx = username.indexOf("\\");
  1222.             if (idx == -1) {
  1223.                 aAuthInfo.username = username;
  1224.             } else {
  1225.                 aAuthInfo.domain   =  username.substring(0, idx);
  1226.                 aAuthInfo.username =  username.substring(idx+1);
  1227.             }
  1228.         } else {
  1229.             aAuthInfo.username = username;
  1230.         }
  1231.         aAuthInfo.password = password;
  1232.     }
  1233.  
  1234. }; // end of LoginManagerPrompter implementation
  1235.  
  1236.  
  1237. var component = [LoginManagerPromptFactory, LoginManagerPrompter];
  1238. function NSGetModule(compMgr, fileSpec) {
  1239.     return XPCOMUtils.generateModule(component);
  1240. }
  1241.